package com.xingkeduo.gateway.authority.service;

import java.security.KeyPair;

import javax.annotation.Resource;

import org.springframework.stereotype.Component;

import com.xingkeduo.dao.cache.CacheDao;
import com.xingkeduo.gateway.authority.pojo.Token;
import com.xingkeduo.util.pojo.enums.YesNoEnum;
import com.xingkeduo.util.pojo.exception.AuthorityException;
import com.xingkeduo.util.tool.EncryptUtil;
import com.xingkeduo.util.tool.EncryptUtil.KeyType;

/**
 * 
 * @author GJ
 * @time 2019年1月22日 下午4:33:22
 * @description
 */
@Component
public class AuthService {
	/**
	 * redisDao ehCacheDao
	 */
	@Resource(name = "redisDao")
	private CacheDao<?, ?> cacheDao;
	private static final String PREFIX = "token";

	/**
	 * 创建授权
	 * 
	 * @author GJ
	 * @time 2019年4月1日 下午2:00:03
	 * @param token
	 * @throws Throwable
	 */
	public void createToken(Token token) throws Throwable {
		initToken(token);
		createRefreshToken(token);
		createAccessToken(token);
	}

	/**
	 * 初始化密钥对
	 * 
	 * @author GJ
	 * @time 2019年1月21日 下午7:01:35
	 * @param key
	 * @return
	 * @throws Throwable
	 */
	public void initToken(Token token) throws Throwable {
		token.setKeyTime(System.currentTimeMillis());
		KeyPair keyPair = EncryptUtil.initKeyPair(buildSeed(token.getUid(), token.getKeyTime()));
		token.setPublicKey(EncryptUtil.getPublicKey(keyPair));
		token.setPrivateKey(EncryptUtil.getPrivateKey(keyPair));
	}

	/**
	 * 创建refreshtoken
	 * 
	 * @author GJ
	 * @time 2019年3月30日 下午2:14:24
	 * @param refreshtoken
	 * @throws Throwable
	 */
	public void createRefreshToken(Token token) throws Throwable {
		token.setRefreshTime(System.currentTimeMillis());
		token.setRefreshToken(
				EncryptUtil.createSign(token.getPrivateKey(), buildSeed(token.getUid(), token.getRefreshTime())));
	}

	/**
	 * 验证refreshToken
	 * 
	 * @author GJ
	 * @time 2019年1月23日 上午11:33:34
	 * @param refreshToken
	 * @return
	 * @throws Throwable
	 */
	public boolean verifyRefreshToken(Token token) throws Throwable {
		Token tokenCache = (Token) cacheDao.get(PREFIX + token.getUid(), YesNoEnum.YES);
		if (tokenCache == null)
			throw new AuthorityException(AuthorityException.Type.LOGIN);

		return EncryptUtil.verifySign(tokenCache.getPublicKey(), buildSeed(token.getUid(), tokenCache.getRefreshTime()),
				token.getRefreshToken());
	}

	/**
	 * 创建access_token
	 * 
	 * @author GJ
	 * @time 2019年1月22日 下午6:57:53
	 * @return
	 * @throws Throwable
	 */
	public void createAccessToken(Token token) throws Throwable {
		token.setAccessTime(System.currentTimeMillis());
		token.setAccessToken(EncryptUtil.encrypt(KeyType.PUBLIC, token.getPublicKey(),
				buildSeed(token.getUid(), token.getAccessTime())));

		cacheDao.set(token.getAccessToken(), token.getUid(), 0l, YesNoEnum.NO);
		Object accessToken = cacheDao.get(PREFIX + token.getUid(), YesNoEnum.NO);
		if (accessToken != null)
			cacheDao.remove(accessToken.toString(), YesNoEnum.NO);
		cacheDao.set(PREFIX + token.getUid(), token.getAccessToken(), 0l, YesNoEnum.NO);
	}

	/**
	 * 验证accessToken
	 * 
	 * @author GJ
	 * @time 2019年1月23日 上午11:33:34
	 * @param accessToken
	 * @return
	 * @throws Throwable
	 */
	public String verifyAccessToken(Token token) throws Throwable {
		Object uid = cacheDao.get(token.getAccessToken(), YesNoEnum.NO);
		if (uid == null)
			throw new AuthorityException(AuthorityException.Type.LOGIN);
		return uid.toString();
	}

	/**
	 * 验证accessToken
	 * 
	 * @author GJ
	 * @time 2019年1月23日 上午11:33:34
	 * @param accessToken
	 * @return
	 * @throws Throwable
	 */
	public void clearAccessToken(Token token) throws Throwable {
		Object uid = cacheDao.get(token.getAccessToken(), YesNoEnum.NO);
		cacheDao.remove(PREFIX + uid, YesNoEnum.NO);
		cacheDao.remove(token.getAccessToken(), YesNoEnum.NO);
	}

	/**
	 * 拼装seed
	 * 
	 * @author GJ
	 * @time 2019年1月22日 下午4:25:30
	 * @param scretPart
	 * @return
	 */
	private String buildSeed(String uid, long time) {
		return new StringBuffer().append(uid).append("=").append(time).toString();
	}
}
